//
//  WLDownloadWorker.m
//  WanLian
//
//  Created by 123456 on 2019/1/4.
//  Copyright © 2019 wanlian. All rights reserved.
//

#import "WLDownloadWorker.h"
#import "WLRecallModel.h"
#import "WLFileRequest.h"
#import "WLSocketPacketParser.h"
#import "WLFileTransportHeadModel.h"
#import "WLFileHandle.h"
#import "WLSaveAblumToLocal.h"
#define HEAD_DATA 0x76
#define HEAD_VERSION 0x01
#define HEAD_TYPE 0x02
@interface WLDownloadWorker ()
@property (nonatomic, strong) NSMutableData *receiveData;
@property (nonatomic, strong) NSMutableArray *receiveArr;

@end
@implementation WLDownloadWorker
- (NSMutableData *)receiveData {
    if (_receiveData == nil) {
        _receiveData = [[NSMutableData alloc] init];
    }
    return _receiveData;
}
- (instancetype)init {
    if (self = [super init]) {
        workerSocketQueue = dispatch_get_main_queue();
    }
    return self;
}
- (WLSocketWorker *)configDownloadWorkerWithFIFOModel:(WLFileRequest *)model
                                     progress:(void (^)(float process, long expected, long loaded))progress
                                      success:(void (^)(NSDictionary *successDict))success
                                      failure:(void (^)(NSString *errorMsg, NSInteger errorTag))failure
                                        error:(void (^)(NSError *error))err {
    self.requestModel = model;
    self.recallModel = [WLRecallModel createWithDownloadProgressBlock:progress successBlock:success faliureBlock:failure errorBlock:err];
    [self Client_init];
    self.requestModel.workingState = WLWorkingStateReadySend;
    return self;
}

- (void)sendFileInfoWithType:(NSString *)type tag:(long)tag{
    if ([type isEqualToString:DEVICE_FILE_DOWNLOAD_REQ]) {
        [self configRequestInfo];
    }
    
    NSNumber *sizeNum = [WLFileHandle sizeOfItemAtPath:self.requestModel.fileURL.path error:nil];
    if (sizeNum) {
        self.requestModel.offset = [sizeNum longValue];
    } else {
        self.requestModel.offset = 0;
    }
    NSData * fileInfo = [self.requestModel getFileTransmitHeadDataWithType:type];
    NSData * headData = [self configHeadProtocolWithData:fileInfo];
    [self.currentSocket writeData:headData withTimeout:SocketTimeOut tag:tag];
}
- (NSURL *)createFileURL {
    
    NSString *documentPath = [WLFileHandle documentsDir];
    NSString *string = nil;
    if (self.requestModel.fileType == 0) {
        string = @"video";
    } else if (self.requestModel.fileType == 1) {
        string = @"photo";
    } else if (self.requestModel.fileType == 2) {
        string = @"music";
    }
    documentPath = [documentPath stringByAppendingPathComponent:string];
    NSString *filePath = [documentPath stringByAppendingPathComponent:self.requestModel.fileName];
    LHLog(@"filePath == %@", filePath);
    
    return [NSURL fileURLWithPath:filePath];
}
- (void)configRequestInfo {
    if (self.requestModel.fileURL == nil) {
        self.requestModel.fileURL = [self createFileURL];
    }
    if (![WLFileHandle isExistsAtPath:self.requestModel.fileURL.path]) {
        NSError *error = nil;
        [WLFileHandle createFileAtPath:self.requestModel.fileURL.path overwrite:NO error:&error];
        if (error) {
            if (self.recallModel.faliureBlock) {
                self.recallModel.faliureBlock(@"生成文件目录失败", FileTransportCreateFileError);
            }
            return;
        }
    }
    
}
- (void)dealWithFileData:(NSData *)resData messageDict:(NSDictionary *)msgDict{
    NSDictionary *dictionary = msgDict;
    WLSocketModel *messageModel = [WLSocketModel mj_objectWithKeyValues:dictionary];
    if ([messageModel.type isEqualToString:DEVICE_FILE_DOWNLOAD_CHECK]) {
        NSDictionary *contentDict = [messageModel.content jsonObject];
        if (contentDict) {
            if ([contentDict[@"resultCode"] integerValue] == 1) {
                
                [self sendFileInfoWithType:DEVICE_FILE_DOWNLOAD_REQ tag:GetFileDataTag];
            }
        } else {
            if (self.fileTransportFailureBlock) {
                self.fileTransportFailureBlock(contentDict[@"resultMsg"], FileTransportErrorTypeServer);
            }
        }
    } else if ([messageModel.type isEqualToString:DEVICE_FILE_DOWNLOAD_RSP]) {
        [self saveFileData:resData megDict:msgDict];
    }
}
- (void)saveFileData:(NSData *)fileData megDict:(NSDictionary *)msgDict {
    
    
//    [self sendFileInfoWithType:DEVICE_FILE_DOWNLOAD_REQ tag:GetFileDataTag];
    if (self.fileHandle == nil) {
        NSError *error = nil;
        if ([WLFileHandle isExistsAtPath:self.requestModel.fileURL.path]) {
            self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:self.requestModel.fileURL.path];
        }
        [self.fileHandle truncateFileAtOffset:0];
        if (error) {
            if (self.recallModel.faliureBlock) {
                self.recallModel.faliureBlock(@"生成文件句柄失败", FileTransportReadingError);
            }
        }
    }
    if (self.fileHandle && msgDict[@"content"] && fileData.length > 0) {
        NSData *contentData = [msgDict[@"content"] dataUsingEncoding:NSUTF8StringEncoding];
        NSDictionary *contentDict = [NSJSONSerialization JSONObjectWithData:contentData options:NSJSONReadingAllowFragments error:nil];
        int fileTotalSize = [contentDict[@"total"] intValue];
        int offset = [contentDict[@"offset"] intValue];
        int slicesSize = [contentDict[@"size"] intValue];
        self.requestModel.fileTotalBytes = fileTotalSize;
//        if (offset > 0) {
            [self.fileHandle seekToFileOffset:offset];
//        }
//        [self.fileHandle seekToEndOfFile];
        [self.fileHandle writeData:fileData];
        int realFileSize = [[WLFileHandle sizeOfItemAtPath:self.requestModel.fileURL.path error:nil] intValue];
        LHLog(@"offset ==%d fileTotalSize == %d realFileSize == %d slicesSize == %d", offset, fileTotalSize, realFileSize, slicesSize);
        if (fileTotalSize > 0 && fileTotalSize == (offset + slicesSize)) {//传输完成
            if (fileTotalSize == realFileSize) {
                [self.fileHandle closeFile];
                [self sendFileInfoWithType:DEVICE_FILE_DOWNLOAD_RSP tag:GetFileCompleteTag];
                [self dealWithSendComplete];
            } else {//本地数据异常
                
                [self sendFileInfoWithType:DEVICE_FILE_DOWNLOAD_RSP tag:GetFileCompleteTag];
                if (self.recallModel.faliureBlock) {
                    self.recallModel.faliureBlock(@"接收数据异常", FileTransportErrorTypeDataParsaringError);
                }
            }
        } else {
            
            float process = realFileSize * 1.0 / fileTotalSize;
            if (self.recallModel.downloadProgressBlcok) {
                self.recallModel.downloadProgressBlcok(process, fileTotalSize, realFileSize);
            }
        }
    }
    
//    int realFileSize = [[WLFileHandle sizeOfItemAtPath:self.requestModel.fileURL.path error:nil] intValue];
//    NSLog(@"realFileSize == %d", realFileSize);
    /*
    if (msgDict[@"content"]) {
        NSData *contentData = [msgDict[@"content"] dataUsingEncoding:NSUTF8StringEncoding];
        int realFileSize = [[WLFileHandle sizeOfItemAtPath:self.requestModel.fileURL.path error:nil] intValue];
        NSDictionary *contentDict = [NSJSONSerialization JSONObjectWithData:contentData options:NSJSONReadingAllowFragments error:nil];
        int fileTotalSize = [contentDict[@"total"] intValue];
        int offset = [contentDict[@"offset"] intValue];
        int slicesSize = [contentDict[@"size"] intValue];
        self.requestModel.fileTotalBytes = fileTotalSize;
        LHLog(@"offset ==%d fileTotalSize == %d realFileSize == %d", offset, fileTotalSize, realFileSize);
        if (fileTotalSize > 0 && fileTotalSize == (offset + slicesSize)) {//传输完成
            if (fileTotalSize == realFileSize) {
                [self sendFileInfoWithType:DEVICE_FILE_DOWNLOAD_RSP tag:GetFileCompleteTag];
                [self dealWithSendComplete];
            } else {//本地数据异常
                [self sendFileInfoWithType:DEVICE_FILE_DOWNLOAD_RSP tag:GetFileCompleteTag];
            }
        } else {
            float process = realFileSize * 1.0 / fileTotalSize;
            if (self.recallModel.downloadProgressBlcok) {
                self.recallModel.downloadProgressBlcok(process, fileTotalSize, realFileSize);
            }
        }
    }*/
}

- (void)dealWithSendComplete {
    [self clearTimer];
    if (self.requestModel.requestConfig.saveToAbulm == YES) {
        
        WLSaveAblumToLocal *library = [[WLSaveAblumToLocal alloc] init];
        if (self.requestModel.fileType == 0) {
            
            [library writeVideoAtPathToSavedPhotosAlbum:self.requestModel.fileURL completionBlock:^(NSURL *assetURL, NSError *error, NSString *localIdentifier) {
                
                [self saveAblumComplete:assetURL error:error localIndentifier:localIdentifier];
            }];
        } else if(self.requestModel.fileType == 1) {
            [library writeImageDataToSavedPhotosAlbumWithURL:self.requestModel.fileURL metadata:[NSDictionary dictionary] completionBlock:^(NSURL * _Nonnull assetURL, NSError * _Nonnull error, NSString * _Nonnull localIdentifier) {
                
                [self saveAblumComplete:assetURL error:error localIndentifier:localIdentifier];
            }];
        }
    } else {
        [self saveAblumComplete:nil error:nil localIndentifier:nil];
    }
    
}
- (void)saveAblumComplete:(NSURL *)assetURL error:(NSError *)error localIndentifier:(NSString *)localIndentifier {
    NSMutableDictionary *muDict = [NSMutableDictionary dictionary];
    self.requestModel.mediaLocalURL = assetURL;
    if (assetURL) {
        NSError *error = nil;
        [WLFileHandle removeItemAtPath:self.requestModel.fileURL.path error:&error];
        [muDict setObject:assetURL forKey:@"localMediaURL"];
    }
    if (localIndentifier) {
        [muDict setObject:localIndentifier forKey:@"localIndentifier"];
    }
    if(self.requestModel.fileURL && assetURL == nil){
        [muDict setObject:self.requestModel.fileURL forKey:@"localURL"];
    }
    if (self.recallModel.successBlock) {
        self.recallModel.successBlock([muDict copy]);
    }
    
}
- (NSDictionary *)getSuccessDictWithLocalURL:(NSURL *)localURL mediaURL:(NSURL *)mediaURL {
    NSMutableDictionary *resDict = [NSMutableDictionary dictionary];
    if (localURL) {
        [resDict setObject:localURL forKey:@"localURL"];
    }
    if (mediaURL) {
        [resDict setObject:mediaURL forKey:@"localMediaURL"];
    }
    return resDict;
}
#pragma mark - GCDAsyncSocketDelegate
/**
 * Called when a socket connects and is ready for reading and writing.
 * The host parameter will be an IP address, not a DNS name.
 **/
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
    [super socket:sock didConnectToHost:host port:port];
    if (sock == self.currentSocket) {
        [self sendFileInfoWithType:DEVICE_FILE_DOWNLOAD_HEAD tag:GetFileHeadTag];
    }
    
//    [self sendFileInfoWithType:DEVICE_FILE_DOWNLOAD_REQ tag:GetFileDataTag];
    
    [self listenDataWithTag:GetFileDataTag];
}

- (BOOL)headValidityJudge:(NSData *)data {
    if (data.length > 12) {
        int32_t value = [data readIntWithLocation:0];
        int32_t version = [data readIntWithLocation:4];
        int32_t msgType = [data readIntWithLocation:8];
        if (value==HEAD_DATA && version== HEAD_VERSION && msgType == HEAD_TYPE) {
            return YES;
        }
    }
    return NO;
}
delay_property_impl(NSMutableArray, receiveArr)

/**
 * Called when a socket has completed reading the requested data into memory.
 * Not called if there is an error.
 **/
- (NSData *)getData {
    NSMutableData *data = [NSMutableData data];
    for (NSData *subData in self.receiveArr) {
        [data appendData:subData];
    }
    return data;
}

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    [super socket:sock didReadData:data withTag:tag];
    if (flag == YES) {
        return;
    }
    LHLog(@"didReadData length = %ld", data.length);
    if (self.parser == nil) {
        WLWkSelf
        self.parser = [[WLSocketPacketParser alloc] initWithParserResultBlock:^(NSDictionary *msgDict, NSData *fileData, WLParserStatus status) {
            if (status == WLParserStatusSucess) {
                NSDictionary *dictionary = msgDict;
                WLSocketModel *messageModel = [WLSocketModel mj_objectWithKeyValues:dictionary];
                if ([messageModel.type isEqualToString:DEVICE_FILE_DOWNLOAD_RSP]) {
                    [weakSelf saveFileData:fileData megDict:msgDict];
                } else if ([messageModel.type isEqualToString:DEVICE_FILE_DOWNLOAD_CHECK]) {
                    if ([dictionary[@"content"] isKindOfClass:[NSString class]]) {
                        NSDictionary *contentDict = [dictionary[@"content"] jsonObject];
                        if ([contentDict[@"resultCode"] integerValue] ==1) {
                            long fileSize = [[WLFileHandle sizeOfItemAtPath:self.requestModel.fileURL.path error:nil] longValue];
                            if (contentDict[@"totalSize"] && [contentDict[@"totalSize"] longValue] == fileSize) {
                                [weakSelf dealWithSendComplete];
                            } else  if (fileSize > [contentDict[@"totalSize"] longValue]) {
                                [WLFileHandle removeItemAtPath:weakSelf.requestModel.fileURL.path error:nil];
                                if (weakSelf.recallModel.faliureBlock) {
                                    weakSelf.recallModel.faliureBlock(@"文件数据错误，下载失败，请重新下载", FileTransportErrorTypeServer);
                                }
                            }
                            else {
                                [weakSelf sendFileInfoWithType:DEVICE_FILE_DOWNLOAD_REQ tag:tag];
                            }
                        }else {
                            if (weakSelf.recallModel.faliureBlock) {
                                weakSelf.recallModel.faliureBlock(contentDict[@"resultMsg"], FileTransportErrorTypeServer);
                            }
                        }
                    }else {
                        if (weakSelf.recallModel.faliureBlock) {
                            weakSelf.recallModel.faliureBlock(@"数据解析错误", FileTransportErrorTypeDataParsaringError);
                        }
                    }
                } else if ([messageModel.type isEqualToString:DEVICE_FILE_DOWNLOAD_RSP]) {
                    [weakSelf saveFileData:fileData megDict:msgDict];
                } else {
                    if (weakSelf.recallModel.faliureBlock) {
                        weakSelf.recallModel.faliureBlock(@"数据解析错误", FileTransportErrorTypeDataParsaringError);
                    }
                }
            } else {
                if (weakSelf.recallModel.faliureBlock) {
                    weakSelf.recallModel.faliureBlock(@"数据解析错误", FileTransportErrorTypeDataParsaringError);
                }
            }
        }];
    }
    [self.parser readData:data withSocket:sock tag:tag];
   /*
    [self.receiveData appendData:data];
    dispatch_async(dispatch_queue_create([@"ParserQueue" UTF8String], NULL), ^{
        int protocolHeadLen = 12;
        int protocolLen = 24;
    
        while (1) {
            if (self.receiveData.length < protocolLen) {
                return;
            }
            if ([self headValidityJudge:self.receiveData]) {
                break;
            } else {
                if (self.receiveData.length > 4) {
                    [self.receiveData removeDataWithRange:NSMakeRange(0, 4)];
                }
            }
        }
        int32_t totalLength = [self.receiveData readIntWithLocation:protocolHeadLen];
        long realPackLen = totalLength + protocolLen;
        if (self.receiveData.length - protocolLen >= totalLength) {//为完全包，不需要粘包
            NSData *subData = [self.receiveData subdataWithRange:NSMakeRange(0, realPackLen)];
            WLWkSelf
            dispatch_async(dispatch_queue_create([@"WLParserPacket" UTF8String], NULL), ^{
                [weakSelf socket:sock parsePackage:subData withTag:tag];
            });
            NSData *leftData = [self.receiveData subdataWithRange:NSMakeRange(realPackLen, self.receiveData.length - realPackLen)];
            [self.receiveData removeAllData];
            if (leftData.length > 0) {
                [self.receiveData appendData:leftData];
                [self socket:sock didReadData:[NSData data] withTag:tag];
            }
        }
    });*/
//    [sock readDataWithTimeout:SocketTimeOut tag:tag];
    [self listenDataWithTag:tag];
}
- (void)listenDataWithTag:(long)tag {
    [self.currentSocket readDataWithTimeout:-1 tag:tag];
//    [self.currentSocket readDataToData:[self headData] withTimeout:-1 tag:tag];
}
- (void)socket:(GCDAsyncSocket *)socket parsePackage:(NSData *)data withTag:(long)tag
{
    
    int protocolLen = 24;
    
    int32_t totalLength = [data readIntWithLocation:12];
    int32_t msgLength = [data readIntWithLocation:16];
    int32_t dataLength = [data readIntWithLocation:20];
    NSDictionary *msgDict = nil;
    NSData *fileData = nil;
    if (data.length - protocolLen == totalLength) {//为完全包，不需要粘包
        if (data.length - protocolLen >= msgLength) {
            NSData *msgData = [data subdataWithRange:NSMakeRange(protocolLen, msgLength)];
            NSString *strData = [[NSString alloc] initWithData:msgData encoding:NSUTF8StringEncoding];
            if (!strData) {
                LHLog(@"解析失败");
                [self dealWithFileData:nil messageDict:nil];
                return;
            }
            NSString *strTrim =[strData stringByTrimmingCharactersInSet:[NSCharacterSet controlCharacterSet]];
            NSData *dataJson = [strTrim dataUsingEncoding:NSUTF8StringEncoding];
            NSError *error;
            msgDict =[NSJSONSerialization JSONObjectWithData:dataJson options:NSJSONReadingMutableLeaves|NSJSONReadingAllowFragments error:&error];
            if (!msgDict || error) {//解析失败
                LHLog(@"解析失败");
                [self dealWithFileData:nil messageDict:nil];
                return;
            }
            long fileDataBeginIndex = protocolLen + msgLength;
            if (dataLength > 0 && (data.length - fileDataBeginIndex == dataLength)) {
                fileData = [data subdataWithRange:NSMakeRange(fileDataBeginIndex, dataLength)];
            }
            [self dealWithFileData:fileData messageDict:msgDict];
//            if (self.parserResBlock) {
//                self.parserResBlock(msgDict, fileData, WLParserStatusSucess);
//            }
        }
    }
}
- (NSMutableData *)headData {
    NSMutableData *data = [NSMutableData data];
    [data appendInt:0x76];
    [data appendInt:0x01];
    [data appendInt:0x02];
    return data;
}

/**
 * Called when a socket has completed writing the requested data. Not called if there is an error.
 **/
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
    [super socket:sock didWriteDataWithTag:tag];
    
    [sock readDataWithTimeout:SocketTimeOut tag:tag];
//    [sock readDataWithTimeout:-1 buffer:self.buffer bufferOffset:0 maxLength:100*1024*1024 tag:100];
}

- (void)dealWithTransporting {
    long sendedTotalSize = 0;
    for (WLFileTransportHeadModel *blockModel in self.requestModel.blockModelArr) {
        sendedTotalSize += blockModel.sendedSize;
    }
    if (self.recallModel.progressBlcok) {
        float process = sendedTotalSize * 1.0 / self.requestModel.fileTotalBytes;
        self.recallModel.progressBlcok(process);
    }
    if (sendedTotalSize == self.requestModel.fileTotalBytes) {// 传输完成
        if (self.fileTransportCompleteBlock) {
            self.fileTransportCompleteBlock();
        }
    }
}

- (void)dealloc {
    [self clearTimer];
}
@end
